// 简单工厂类
// 来源： https://zhuanlan.zhihu.com/p/83535678
// 略微修改，不用里面的switch-case

//
//        Shoes
//      /   |   \
//  Nike Adidas  LiNing
//    |     |      |
//     |    |     |
//      \   |  /
//     ShoesFactory

#include <iostream>

class Shoes {
   public:
    //
    virtual ~Shoes() = default;
    virtual void show() const = 0;
};

class NikeShoes : public Shoes {
   public:
    void show() const { std::cout << "Nike shoes " << std::endl; }
};

class AdidasShoes : public Shoes {
   public:
    void show() const { std::cout << "Adidas shoes" << std::endl; }
};

class LiNingShoes : public Shoes {
   public:
    void show() const { std::cout << "Lining shoes" << std::endl; }
};

enum SHOES_TYPE { NIKE, LINING, ADIDAS };

class shoesFactory {
   public:
   // method 1
    shoesFactory(Shoes* pShoes) : pShoes_(pShoes) {}
    shoesFactory() = default;
    // 根据鞋子类型创建对应的鞋子对象

   // method 2 
   // 这种是比较正常的工厂模式，但是对于子类很多的情况
   // 会有一定的问题：
   // https://www.bilibili.com/video/BV1e5411R7ZH/?spm_id_from=333.337.search-card.all.click&vd_source=16b267e92edd288778342448b69d98f9
    static Shoes* CreateShoes(SHOES_TYPE type) {
        switch (type) {
            case NIKE:
                return new NikeShoes();
                break;
            case LINING:
                return new LiNingShoes();
                break;
            case ADIDAS:
                return new AdidasShoes();
                break;
            default:
                return NULL;
                break;
        }
    }

    void showShoes() const { pShoes_->show(); }

   private:
    Shoes* pShoes_;
};

int main() {
    // method 1
    Shoes* shoes = new NikeShoes;
    shoesFactory pShoesObj(shoes);
    pShoesObj.showShoes();
    // delete shoes; //管理内存不嘞...

    // method 1
    Shoes* shoes2 = new LiNingShoes;
    shoesFactory pShoesObj2(shoes2);
    pShoesObj2.showShoes();

    // 2
    // 把CreateShoes定义为static，可以直接用类名来调用
    // shoesFactory test;
    Shoes* pAidas = shoesFactory::CreateShoes(ADIDAS);
    // test.showShoes();
    pAidas->show();
}